package com.heima.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heima.article.entity.ApArticle;
import com.heima.article.entity.ApArticleContent;
import com.heima.article.entity.ApAuthor;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleContentService;
import com.heima.article.service.ApArticleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.service.ApAuthorService;
import com.heima.article.service.FreeMarkerService;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.util.BeanHelper;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.media.dtos.WmNewsResultDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 文章信息表，存储已发布的文章 服务实现类
 * </p>
 *
 * @author LX
 * @since 2022-06-20
 */
@Slf4j
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    private ApArticleContentService contentService;
    @Autowired
    private ApAuthorService apAuthorService;
    @Autowired
    private FreeMarkerService freeMarkerService;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    /**
     * 保存文章信息
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveArticle(WmNewsResultDTO dto) {
//        自媒体文章id
        Integer wmNewsId = dto.getId();
//        根据自媒体文章id，查询文章信息
        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApArticle::getWmNewsId,wmNewsId);

        ApArticle apArticle = getOne(queryWrapper);
        if(apArticle == null){
//            自媒体文章不存在，新增
            apArticle = new ApArticle();
//            有些数据是新增时需要初始化
//            根据自媒体用户id 查询文章作者id
            ApAuthor apAuthor = apAuthorService.getByWmUserId(dto.getWmUserId());
            if(apAuthor != null) {
                apArticle.setAuthorId(apAuthor.getId());
                apArticle.setAuthorName(apAuthor.getName());
            }
            apArticle.setFlag(0);
            apArticle.setLikes(0L);
            apArticle.setCollection(0L);
            apArticle.setComments(0L);
            apArticle.setViews(0L);
            apArticle.setCreatedTime(new Date());
            apArticle.setOrigin(0);
            apArticle.setIsComment(true);
            apArticle.setIsForward(true);
            apArticle.setIsDown(false);
            apArticle.setIsDelete(false);
            apArticle.setWmNewsId(wmNewsId);
        }
        apArticle.setTitle(dto.getTitle());
        apArticle.setChannelId(dto.getChannelId());
        apArticle.setChannelName(dto.getChannelName());
        apArticle.setLayout(dto.getType());
        apArticle.setImages(dto.getImages());
        apArticle.setLabels(dto.getLabels());
//        如果是立即发布，就设置为当前时间，否则，就用dto的时间
        apArticle.setPublishTime(dto.getPublishTime()==null?new Date():dto.getPublishTime());
//        有些数据是修改和新增都需要填写
//        1、保存/修改文章信息
        boolean b = saveOrUpdate(apArticle);
        if(!b){
            log.error("保存ap_article表失败");
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
//        获取文章id
        Long articleId = apArticle.getId();
//        2、保存/修改文章内容
        ApArticleContent apArticleContent = new ApArticleContent();
        apArticleContent.setArticleId(articleId);
        apArticleContent.setContent(dto.getContent());
        boolean b1 = contentService.saveOrUpdate(apArticleContent);
        if(!b1){
            log.error("保存ap_article_conent表失败");
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }


        Callable<String> callable = new Callable<String>(){
            @Override
            public String call() throws Exception {
//        调用生成文章内容静态页面
                String htmlUrl = freeMarkerService.buildContentHtml(dto.getContent(), articleId);
                log.info("子线程返回的htmlurl={}",htmlUrl);
                return htmlUrl;
            }
        };
//       执行 callable子线程
        Future<String> future = taskExecutor.submit(callable);
        try {
            String htmlUrl = future.get(2, TimeUnit.SECONDS);
//        保存文章静态页路径
            ApArticle apArticleUrl = new ApArticle();
            apArticleUrl.setId(articleId);
            apArticleUrl.setStaticUrl(htmlUrl);
            boolean b2 = updateById(apArticleUrl);
        }catch (Exception e){
            log.error("获取子线程结果失败！");
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR);
        }
        return articleId;
    }

    /**
     * 文章列表首页
     * @param dto
     * @param type  1- 首页上拉 2 下拉
     * @return
     */
    @Override
    public List<ArticleDto> load(ArticleHomeDto dto,int type) {
//        分页条件
        Page<ApArticle> ipage = new Page<>(1,dto.getSize());
//        查询条件
        LambdaQueryWrapper<ApArticle> queryWrapper = new LambdaQueryWrapper<>();
//        查询 没有下架 ，没有删除的文章
        queryWrapper.eq(ApArticle::getIsDown,false).eq(ApArticle::getIsDelete,false);
//        添加channelId条件  0-推荐频道，就是不分频道全部都查，如果不是0 需要根据channelid查询
        queryWrapper.eq(dto.getChannelId() !=0,ApArticle::getChannelId,dto.getChannelId());
//        首页查询的时候，需要查询发布时间小于minTime的文章
        if(type==1) {
            queryWrapper.lt(ApArticle::getPublishTime, dto.getMinTime());
        }else{
            queryWrapper.gt(ApArticle::getPublishTime,dto.getMaxTime());
        }
//        按照发布时间倒叙
        queryWrapper.orderByDesc(ApArticle::getPublishTime);
//        分页查询
        IPage<ApArticle> apArticleIPage = page(ipage, queryWrapper);
        if(apArticleIPage == null || CollectionUtils.isEmpty(apArticleIPage.getRecords())){
            log.error("文章数据不存在");
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
//        构造返回对象
        List<ApArticle> apArticleList = apArticleIPage.getRecords();
        List<ArticleDto> articleDtoList = BeanHelper.copyWithCollection(apArticleList, ArticleDto.class);
        return articleDtoList;
    }

    @Override
    public void upOrDown(Map<String, Long> map) {
        //        map  key  - articleId    key - enable value - 1 :上架  0：下架
        UpdateWrapper<ApArticle> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().
                eq(ApArticle::getId,map.get("articleId")).
                set(ApArticle::getIsDown,map.get("enable").intValue()==1?false:true);
        update(updateWrapper);
    }

    @Override
    public List<ArticleDto> findByPage(Integer page, Integer size) {
        //        设置分页条件
        Page<ApArticle> ipage = new Page<>(page,size);
//        分页查询
        IPage<ArticleDto> articleIPage = baseMapper.selectArticleAndContentByPage(ipage);
        if(articleIPage != null && !CollectionUtils.isEmpty(articleIPage.getRecords())){
            return articleIPage.getRecords();
        }
//        构造返回对象
        return null;
    }
}
